#include "preloader.h"
#include <semaphore.h>
#include <pthread.h>
#define PRELOADER_VERSION "preloader V1.0, Copyright (C) 2012 ChinaCache"

static const char helper_info[] = 
"\t-h, --help	print the help massage\n"
"\t-p, --port	listen port\n"
;

sem_t thread_number;
typesize_t tsize;
preloader_t preloader;
pthread_mutex_t mylock;
pthread_mutex_t myfilelock;
static int refreshd_port = 21108;
static char devid[BUF_SIZE_128];
static char refreshd_ip[BUF_SIZE_16] = "127.0.0.1";
static char refreshClient[] = "/usr/local/squid/bin/refresh_cli";
char store_dir[] = "/tmp/preloader";


static char *xcalloc(size_t n, size_t sz)
{
	void *ptr;

	ptr = calloc(n, sz);
	if (NULL == ptr)
	{
		plog(ERROR, "xcalloc failed, exiting now, ERROR=[errno]", strerror(errno));
		exit(1);
	}
	return ptr; 	
}

static char *xstrdup(const char *src)
{
	void *dst;
	size_t size;

	if (NULL == src)
	{
		plog(ERROR, "xstrcpy(NULL), usage error, exiting now");
		exit(1);
	}
	size = strlen(src) + 1;
	dst = xcalloc(size, 1);

	return memcpy(dst, src, size);
}

static void getDevId(void)
{
	FILE *fp = NULL; 

	fp = fopen("/sn.txt", "r");
	if (NULL == fp)
	{
		plog(ERROR, "fopen(\"/sn.txt\") failed[%s]", strerror(errno));
		exit(1);
	}
	memset(devid, 0, BUF_SIZE_128);
	fgets(devid, BUF_SIZE_128, fp);
	devid[strlen(devid) - 1] = '\0'; 
	fclose(fp);
}

static int checkDirectory(const char *dir)
{
	struct stat st; 

	if (stat(dir, &st) < 0)
	{
		if (mkdir(dir, 0755) < 0)
		{       
			fprintf(stderr, "mkdir() failed, DIR=[%s], ERROR=[%s]", dir, strerror(errno));
			return -1;
		}
	}

	return 0;
}

static int packSendData(task_t *task, url_node_t *node)
{

	void *ptr = NULL;
	size_t datalen, size;
	char result[BUF_SIZE_512];

	memset(result, 0, BUF_SIZE_512);
	snprintf(result, BUF_SIZE_512,
			"    <url_ret url=\"%s\">%s</url_ret>\n", node->url, node->code);


	datalen = strlen(result);
	size = task->buflen + datalen + 1;
	
	ptr = (NULL == task->buf) ? xcalloc(size, 1) : realloc(task->buf, size);
	if (NULL == ptr)
	{
		plog(ERROR, "xalloc() or realloc() failed, ERROR=[%s]", strerror(errno));
		return -1;
	}
	
	task->buf = ptr;
	memcpy(task->buf + task->buflen, result, datalen + 1);
	task->buflen = strlen(task->buf);

	//printf("task->buf::%s\n", task->buf);
	//free(task->buf);
	//printf("task->buf is free\n");
	//task->buf = NULL;

	return 0;

}




static int http_post(task_t* task,char* uri,char* host,int port)
{

	int  ret = 0;
	struct sockaddr_in servaddr;
	int str2_len;
	int n=0;
	char buf[1024];
	str2_len = strlen(task->buf);
	int mysockfd = -1;

	char *str;
	char str2[str2_len + 128];
	char str1[str2_len + 1024];
	char *p;


	struct sigaction act;
	memset(&act, 0, sizeof(act));


	socklen_t len;

	
	struct hostent* alert_hostent = gethostbyname(host);
	char* ip = inet_ntoa(*((struct in_addr *)alert_hostent->h_addr));	
	if(ip == NULL)
	{
		printf("inet_ntoa error: %s\n", strerror(errno));
		plog(ERROR, "inet_ntoa error %s\n", strerror(errno));
		return -1;

	}
	if ((mysockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) 
		{
		plog(ERROR, "create socket error, %s", strerror(errno));
		return -1;
	}



	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	if (inet_pton(AF_INET, ip, &servaddr.sin_addr) <= 0 )
	{
		plog(ERROR, "inet_pton error: %s\n", strerror(errno));
	}


	if (connect(mysockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
		plog(ERROR, "connect error : %s\n", strerror(errno));
		close(mysockfd);
		return -1;
	}

	memset(str1, 0, sizeof(str1));
	memset(str2, 0, sizeof(str2));

	
	strcat(str2, task->buf);


	str=(char *)malloc(128);
	if(str == NULL)
	{
	plog(ERROR, "malloc str error");
	close(mysockfd);
	return -1;
	}

	len = strlen(str2)+4 + strlen(task->passwd) + 10;

	sprintf(str, "%d", len);
	strcat(str1, "POST ");
	strcat(str1,uri);
	strcat(str1," HTTP/1.1\r\n");
	strcat(str1, "Accept: */*\r\n");
	strcat(str1, "Accept-Language: zh-cn\r\n");
	strcat(str1, "Host: ");
	strcat(str1,host);
	strcat(str1,"\r\n");
	strcat(str1, "Content-Type: application/x-www-form-urlencoded\r\n");
	strcat(str1, "Content-Length: ");
	strcat(str1, str);
	strcat(str1, "\r\nConnection: close");
	strcat(str1, "\r\n\r\n");
	strcat(str1, "xml=");
	strcat(str1, str2);
	strcat(str1, "&passkey=");
	strcat(str1, task->passwd);
	strcat(str1, "\r\n\r\n");


	 ret = send(mysockfd,  str1,  strlen(str1) + 1, 0);
	if (ret < 0)
	{
		fprintf(stderr, "send() failed, ERROR=[%s]\n", strerror(errno));
	}
	else if (0 == ret) 
	{
		plog(ERROR, "send() error, ERROR=[%s]\n", strerror(errno));
	}
	else    
	{
		plog(COMMON, "send() succeed, SENDLEN=[%ld], passkey = %s", ret, task->passwd);
	}


	
	n = read(mysockfd, buf, 1024);
	if(n > 0)
	{
		plog(COMMON, "send ok");

	}
	else if(n == 0)
	{
		plog(WARNING, "sockfd is closed, but send success");
	}
	else
	{
		plog(WARNING, "read answer error, but send success");
	}

	p = strstr(buf, task->passwd);
	if(p!=NULL)
	{
	//plog(COMMON, "receive %s answer success", task->passwd);
	plog(COMMON, "receive %s answer success", task->passwd);
	}
	else
	{
	plog(WARNING, "receive %s answer not success", task->passwd);
	}

	printf("------------send success---------------\n");

	free(str);
	str = NULL;
	close(mysockfd);
	memset(buf, 0, sizeof(buf));	
	return 1;
}



static int postResultToServer(task_t *task)
{
	//char *host = "127.0.0.1";
	char *host = "202.108.251.215";
	char *uri = "/preload/accept_res.php";
	int port = 20129;
	http_post(task,uri,host,port);
	return 0;
}









int mygetrespondcode(char *str, char *code)
{
	char *p;
	char *q;
	char buf[100];
	p = strstr(str, "\r\n");
	strncpy(buf, str, p-str);
	buf[p-str] = '\0';
	p = strchr(buf, ' ');
	q = strchr(p+1, ' ');
	strncpy(code, p+1, 3);
	code[3] = '\0';
	return 0;
}




int codelink(char *str, int port, char *code)
{
	int sfd, n;
	struct sockaddr_in serv_addr;
	char tmp[4096];


	sfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sfd < 0)
	{
		printf("socket error:%s\n", strerror(errno));
		plog(ERROR, "socket error:%s", strerror(errno));
		return -1;
			
	}

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;

	serv_addr.sin_port = htons(port);
//	n = inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);	
	n = inet_pton(AF_INET, "202.108.251.140", &serv_addr.sin_addr.s_addr);	
	if(n < 0)
	{
		printf("inet_pton error, %s\n", strerror(errno));
		plog(ERROR, "inet_pton error, %s", strerror(errno));
		close(sfd);
		return -1;

	}
	n = connect(sfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr));
	if(n<0)
	{
			n = connect(sfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr));
			if(n<0)
			{
				plog(ERROR, "connect error: %s", strerror(errno));
				close(sfd);
				return -1;
			}
		
	}
	send(sfd, str, strlen(str)+1, 0);

	recv(sfd, tmp, 4096, 0);
	close(sfd);	
	mygetrespondcode(tmp, code);
	return 0;
}













int make_head(char *str, char *code)
{
    char tmpurl[1024];
    char *hostend = NULL;
    char *hostbegin = NULL;
    char *tmpport = NULL;
    int  port;
    char buf[10];
    char headbuf[1024];
    char host[128];
    int httplen;
    int n;
    //int code;

    memset(headbuf, 0, 1024);

    httplen = strlen("http://");
    strcpy(tmpurl, str + httplen);

    hostbegin = tmpurl;

    tmpport = strchr(hostbegin, ':');
    if(tmpport == NULL)
    {
	 port = 80;
   	 hostend = strchr(hostbegin, '/');
	 if(hostend == NULL)
	 {
            strcpy(host, hostbegin);
	    hostend = "/";
         }
	 else
  	 {
    	     strncpy(host, hostbegin, hostend - hostbegin);
  	     host[hostend - hostbegin] = '\0';
         }
    }
    else
       {
		hostend = tmpport;

		strncpy(host, hostbegin, hostend - hostbegin);
  	     	host[hostend - hostbegin] = '\0';
		hostend = strchr(tmpport, '/');
		if(hostend == NULL)
		{
			port = atoi(tmpport+1);
			hostend = "/";
		}
		else
		{	strncpy(buf, tmpport+1, hostend-tmpport);
			port = atoi(buf);
		}
	
       }
	
    strcat(headbuf, "GET ");
    strcat(headbuf, hostend);
    strcat(headbuf, " HTTP/1.1\r\n");
    strcat(headbuf, "Host: ");
    strcat(headbuf, host);
    strcat(headbuf,"\r\nAccept: */*\r\n");
    strcat(headbuf, "Connection: close");
    strcat(headbuf, "\r\n\r\n");

    n = codelink(headbuf, port, code);
    if(n == -1)
    {
         strcpy(code, "000");
    }
    return 0;
}










static int urlPreloadOne(task_t *task, url_node_t *node)
{

	int  type;

	switch (task->method)
	{
		case ACTION_URL_PURGE:
		case ACTION_URL_EXPIRE:
		case ACTION_URL_PRELOAD:
			type = ACTION_URL;
			break;
		case ACTION_DIR_PURGE:
		case ACTION_DIR_EXPIRE:
		case ACTION_DIR_PRELOAD:
			type = ACTION_DIR;
			break;
		default:
			plog(ERROR, "no this method, METHOD=[%d]", task->method);
			return -1;
	}


    make_head(node->url, node->code);


	if (strcmp(node->code, "200"))
	{
		node->status = 0;
		goto RET;
	}




	node->status = 1;

RET:
	packSendData(task, node);
	

	return 0;
}

static int cmp(void *key, void *data)
{
	return *((int *)key) - ((task_t *)data)->sockfd;
}


static int preloaderResetRlimit(void)
{
	struct rlimit rlmt;

	getrlimit(RLIMIT_NOFILE, &rlmt); 
	if (rlmt.rlim_max < PRELOADER_FD_MAX)
	{
		rlmt.rlim_max = PRELOADER_FD_MAX; 
		rlmt.rlim_cur = rlmt.rlim_max;
	}
	if (rlmt.rlim_cur < rlmt.rlim_max)
		rlmt.rlim_cur = rlmt.rlim_max;
	if (setrlimit(RLIMIT_NOFILE, &rlmt) < 0)
	{
		return FAILED;  
	}
	plog(COMMON, "setrlimit() succeed, rlim_cur=[%ld], rlim_max=[%ld]", rlmt.rlim_cur, rlmt.rlim_max);

	return SUCC;
}






static void preloaderKillRunningPort(int port)
{
	FILE *fp = NULL;
	char cmd[BUF_SIZE_128];

	snprintf(cmd, BUF_SIZE_128, "/sbin/fuser -k -9 -n tcp %d 2>&1", port);
	fp  = popen(cmd, "r");
	if(NULL == fp) 
	{
		plog(ERROR, "popen(\"%s\", \"r\") failed, ERROR=[%s]\n", strerror(errno));
		exit(1);
	}
	pclose(fp);
}







void preloaderSafeFree(void **ptr)
{

	if (NULL == ptr || NULL == *ptr)
		return;
	free(*ptr);
	*ptr = NULL;
}


static void preloaderVersion(void)
{
	fprintf(stderr, "%s\n", PRELOADER_VERSION);
}

static void preloaderHelper(void)
{
	fprintf(stderr, "%s", helper_info);
}

static void preloaderParseOptions(int argc, char **argv)
{
	int opt, option_index;
	struct option long_options[] = {
		{"port",    1, NULL, 'p'},
		{"help",    0, NULL, 'h'},
		{"version", 0, NULL, 'v'},
		{0, 0, 0, 0}
	};

	do {    
		
		opt = getopt_long(argc, argv, "p:hv", long_options, &option_index);
		if (-1 == opt)
			break;  
		switch (opt) { 
			case 'h':
				preloaderHelper();
				exit(0);
			case 'p':
				preloader.port = atoi(optarg); 
				break;  
			case 'v':
				preloaderVersion();
				exit(0);
			case ':':
				fprintf(stderr, "option needs a value, OPTION=[%c]\n", opt);
				plog(ERROR, "option needs a value, OPTION=[%c]\n", opt);
				exit(1);
			case '?':
				fprintf(stderr, "unkown command option, OPTION=[%c]", opt);
				plog(WARNING, "unkown command option, OPTION=[%c]", opt);
				exit(1);
		}
	} while (1);
}

static void preloaderSizeFigure(void)
{
	tsize.task_t_size = sizeof(task_t);
	tsize.peek_data_t_size = sizeof(peek_data_t);
}

static void preloaderVarInit(void)
{
	//memset(&preloader, 0, sizeof(preloader));
	preloader.port = LOCAL_DEFAULT_PORT;
	preloaderSizeFigure();
	detectEpollCall(EPOLL_INIT, 0, 0, NULL);
}

static int setSockfdNonblocking(const int sockfd) 
{
	int flags;

	flags = fcntl(sockfd, F_GETFL);
	if (flags < 0)
	{
		plog(ERROR, "fcntl(F_GETFL) failed, ERROR=[%s]", strerror(errno));
		return -1;
	}
	if (fcntl(sockfd, F_SETFL, flags|O_NONBLOCK) < 0)
	{
		plog(WARNING, "fcntl(F_SETFL) failed, ERROR=[%s]", strerror(errno));
		return -1;
	}
	return 0;
}


static int preloaderSetIndexRelease(int sockfd)
{
	int i;

	if (sockfd > preloader.index.max_sockfd)
		return -1;
	preloader.index.idx[sockfd].inuse = 0;
	preloader.index.idx[sockfd].rfc = NULL;
	if (sockfd < preloader.index.max_sockfd)
		return 0;
	for (i = sockfd; i >= 0; --i)
	{
		if (preloader.index.idx[sockfd].inuse)
		{
			preloader.index.max_sockfd = i;
			return 0;
		}

	}
	preloader.index.max_sockfd = 0;
	//preloader.index.idx[sockfd].timestamp = time(NULL);

	return 0;
}


static int preloaderAcceptHandle(int listen_sockfd)
{
	int sockfd;
	struct sockaddr_in peeraddr;
	socklen_t addrlen = sizeof(peeraddr);

	sockfd = accept(listen_sockfd, (void *)&peeraddr, &addrlen);
	if (sockfd < 0)
	{
		plog(ERROR, "accept() failed, ERROR=[%s]", strerror(errno));
		return -1;
	}
	
	if(FAILED == detectEpollCall(EPOLL_ADD, sockfd, EPOLLIN|EPOLLERR|EPOLLHUP, NULL))
	{
		plog(ERROR, "epoll_add error");
	}
	return 0;
	//close(sockfd);
}

static int checkSockfdValid(const int sockfd)
{
	int sock_errno = 0;
	socklen_t sockerr_len = sizeof(sock_errno);

	if (0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &sock_errno, &sockerr_len))
	{
		return FALSE;
	}
	if (0 == sock_errno || EISCONN == sock_errno)
		return TRUE;

	return FALSE;
}

int parsePreloadUrlList(xmlNodePtr cur, xmlDocPtr doc, char *token, task_t *task)
{

	char *c, *d;
	xmlChar *key, *id;
	cur = cur->xmlChildrenNode;

	int b_find = 0;

	while (NULL != cur)
	{
		if (!xmlStrcmp(cur->name, (const xmlChar *)token))
		{
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			if(!(key && xmlStrlen(key)))
			{
				xmlFree(key);
				goto NEXT;
			}
			id = xmlGetProp(cur,(const xmlChar *)"id");
			if(!(id && xmlStrlen(id)))
			{
				xmlFree(id);
				xmlFree(key);
				goto NEXT;
			}
			b_find = 1;
			url_node_t *url = calloc(sizeof(url_node_t), 1);
			if(url == NULL)
			{
				plog(ERROR, "calloc error, %s", strerror(errno));
				xmlFree(id);
				xmlFree(key);
				return -1;
			}
			url->url = calloc(xmlStrlen(key) + 1, 1);
			if(url->url == NULL)
			{
				plog(ERROR, "calloc url->url error, %s", strerror(errno));
				xmlFree(id);
				xmlFree(key);
				free(url);
				return -1;
			}
			strcpy(url->url, (char *)key);
			while(NULL != (c = strstr(url->url,"%26")))
			{
				*c++ = '&';
				d = c + 2;
				while((*d) != '\0') *c++ = *d++;
				*c = '\0';
			}
			//url->len = xmlStrlen(key);
			url->id = strtoll((const char *)id, (char **)NULL, 10);
			url->next = NULL;
			//printf("url->url:::%s\n", url->url);
		

			xmlFree(key);
			xmlFree(id);
			//add to url list

			if(NULL == task->urls.list)
			{
				task->urls.list = url;
				task->urls.head = task->urls.list;
				task->urls.tail = task->urls.list;
			}
			else
			{
				(task->urls.tail)->next = url;
				task->urls.tail = url;
			}
			task->urls.number++;

			//free(url->url);
			//free(url);
			


		}

NEXT:
		cur = cur->next;
	}

	return b_find ? 0 : -1;


}

int parsePreloadUrl(xmlNodePtr cur,xmlDocPtr doc, task_t *task)
{
	int b_url = -1, ret = 0;
	while (NULL != cur)
	{ 
		if (!xmlStrcmp(cur->name, (const xmlChar *)"url_list"))
		{
			ret = parsePreloadUrlList(cur, doc, "url", task);
			if(ret < 0)
			{ 
				b_url = -1;
				send(task->sockfd, "don't have url", 15, 0);
				close(task->sockfd);
				break;  
			}       
			b_url = 0; 
		}       
		cur = cur->next;
	}

/*
	for(tmp=task->urls.head; tmp!=NULL; tmp=tmp->next)
	{
			printf("url ::%s\n", tmp->url);
		//	free(tmp->url);
		//	printf("tmp->url free\n");
		//	free(tmp);
		//	printf("tmp free\n");

	}

*/
	

	return b_url;
}

static int parsePreloadDir(xmlNodePtr cur, xmlDocPtr doc, task_t *task)
{ 
	int b_action = 0;
	int b_dir = 0;

	while (NULL != cur)
	{ 
		if (!xmlStrcmp(cur->name, (const xmlChar *)"action"))
		{
			xmlChar *key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			task->action = strtol((const char *)key, (char **)NULL, 10);
			b_action = 1; 
			xmlFree(key);
		}       
		if (!xmlStrcmp(cur->name, (const xmlChar *)"report_address"))
		{
			xmlChar *key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			strncpy(task->report_address, (char *)key, BUF_SIZE_16); 
			xmlFree(key);
		}
		if (!xmlStrcmp(cur->name, (const xmlChar *)"dir"))
		{
			xmlChar *key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			if(xmlStrlen(key) > strlen("http://"))
			{
				url_node_t * url = calloc(sizeof(url_node_t), 1);
				url->url = calloc(xmlStrlen(key) + 1, 1);
				strcpy(url->url,(char *)key);
				//url->len = xmlStrlen(key);
				task->urls.list = url;
				b_dir = 1;
			}
			else
			{
				plog(WARNING, "invalid url, URL=[%s]", key);
				xmlFree(key);
				return -1;
			}
			xmlFree(key);
		}
		cur = cur->next;
	}

	return (b_action && b_dir);
}

static ssize_t preloaderParseMsgHeaders(char *buffer, peek_data_t *peek)
{
	size_t contlen;
	char *pos, *token;

	pos = strstr(buffer, "\r\n\r\n");
	if (NULL == pos)
	{
		plog(ERROR, "message has no headers from peer");
		return -1;
	}
	peek->hdrlen = pos - buffer + strlen("\r\n\r\n");

//	plog(COMMON, "peek->hdrlen: %ld", peek->hdrlen);
	
	contlen = strlen("Content-Length");
	token = strtok(buffer, "\r\n");
	while (NULL != token)
	{
		if (!strncasecmp(token, "Content-Length", contlen))
		{
			pos = strchr(token, ':');
			if (NULL == pos)
			{
				plog(ERROR, "header 'Content-Length' has wrong format");
				return -1;
			}
			peek->contlen = atol(++pos);
//			plog(COMMON, "Content-Length: %ld", peek->contlen);
			return (peek->contlen < 0) ? -1 : 0;
		}
		token = strtok(NULL, "\r\n");
	}

	return -1;
}

static ssize_t preloaderPeekMsgHeaders(int sockfd, peek_data_t *peek)
{
	ssize_t ret;
	char buffer[BUF_SIZE_2048];

	memset(buffer, 0, BUF_SIZE_2048);
	ret = recv(sockfd, buffer, BUF_SIZE_2048, MSG_PEEK);
	if (ret < 0)
	{
		plog(ERROR, "recv(MSG_PEEK) failed, ERROR=[%s]", strerror(errno));
		return -1;
	}

	return preloaderParseMsgHeaders(buffer, peek);
}

static int preloaderActionAtoi(char *action)
{
	if(!strcasecmp(action, "url_preload"))
		return ACTION_URL_PRELOAD;
	if(!strcasecmp(action, "url_purge"))
		return ACTION_URL_PURGE;
	if(!strcasecmp(action, "url_expire"))
		return ACTION_URL_EXPIRE;
	if(!strcasecmp(action, "dir_purge"))
		return ACTION_DIR_PURGE;
	if(!strcasecmp(action, "dir_expire"))
		return ACTION_DIR_EXPIRE;

	return ACTION_UNKNOWN;
}

static int preloaderParseMsgBody(task_t *task, peek_data_t *peek)
{
	char *bodypos;
	xmlDocPtr doc;
    	xmlNodePtr cur;
	xmlChar *method_name , *sessid;


//	url_node_t *tmp =NULL;

	bodypos = task->buffer + peek->hdrlen;
	strncpy(task->passwd, bodypos, 14);
	task->passwd[14] = '\0';
	//printf("passkey = %s\n", task->passwd);
	bodypos+=14;
	//printf("+++++%s+++++\n", bodypos);
	
	//doc = xmlReadMemory(bodypos,peek->contlen,NULL,"utf8",XML_PARSE_RECOVER);
	doc = xmlParseMemory(bodypos, peek->contlen);
	if (NULL == doc)
	{
		plog(ERROR, "xmlParseMemory() failed, BUFFER=[%s]", task->buffer);
		goto OUT;
	}
	cur = xmlDocGetRootElement(doc);
	if (NULL == cur)
	{
		plog(ERROR, "xmlDocGetRootElement() failed, empty document");
		goto OUT;
	}
	if (xmlStrcmp(cur->name, (const xmlChar *) "method"))
	{
		plog(ERROR, "document has no root node 'method'");
		goto OUT;
	}
	method_name = xmlGetProp(cur,(const xmlChar *)"name");
	//printf("%s\n", method_name);
	if (NULL == method_name)
	{
		plog(ERROR, "no method name");
		goto OUT;
	}
	sessid = xmlGetProp(cur,(const xmlChar *)"sessionid");
	//printf("%s\n", sessid);
	if (NULL == sessid)
	{
		plog(ERROR, "no sessionid");
		xmlFree(method_name);
		goto OUT;
	}


	task->method = preloaderActionAtoi((char *)method_name);
	task->sessionid = xstrdup((char *)sessid);
	xmlFree(method_name);
	xmlFree(sessid);
	cur = cur->xmlChildrenNode;
	//printf("task->method::%d\n", task->method);
	//printf("ACTION_URL_PURGE: %d\n", ACTION_URL_PURGE);

	switch (task->method)
	{
		case ACTION_URL_PURGE:
		case ACTION_URL_EXPIRE:
		case ACTION_URL_PRELOAD:
			if (parsePreloadUrl(cur,doc,  task) < 0)
				goto OUT;
			break;
		case ACTION_DIR_PURGE:
			//plog(WARNING, "Do not support dir purge!");
			goto OUT;
		case ACTION_DIR_EXPIRE:
			//if (parsePreloadDir(cur, doc, task) < 0)
				goto OUT;
			break;
		default:
			//plog(ERROR, "unknown method, METHOD=[%s]", method_name);
			break;
	}


/*
	for(tmp=task->urls.head; tmp!=NULL; tmp=tmp->next)
		{
				printf("url ::%s\n", tmp->url);
	
		}
*/

/*
*/




	xmlFreeDoc(doc);
	return 0;

OUT:
	if (NULL != doc)
	{
		xmlFreeDoc(doc);
		doc = NULL;
	}
	return -1;
}



static int preloaderReleaseTask(task_t *task)
{

	url_node_t *cur, *next;

	if (NULL == task)
		return 0;
	if (NULL != task->buf)
		preloaderSafeFree((void *)&task->buf);
	if (NULL != task->buffer)
		preloaderSafeFree((void *)&task->buffer);
	if (NULL != task->sessionid)
		preloaderSafeFree((void *)&task->sessionid);

	for (cur = task->urls.list; NULL != cur; cur = next)
	{
		next = cur->next;
		preloaderSafeFree((void *)&cur->url);
		preloaderSafeFree((void *)&cur);
	}

	task->buflen = 0;
	task->urls.list = NULL;
	task->urls.head = NULL;
	task->urls.tail = NULL;
	
	preloaderSafeFree((void *)&task);

	return 0;
}




static int packReportData(task_t *task)
{
	char *ptr;
	char hdr_buffer[BUF_SIZE_4096];
	char xml_end[BUF_SIZE_1024];
	char xml_begin[BUF_SIZE_1024];
	size_t total = 0, hdr_len = 0;
	size_t xmlend_len = 0, xmlbegin_len = 0;



	memset(xml_end, 0, BUF_SIZE_1024);
	xmlend_len += sprintf(xml_end + xmlend_len, "</url_preload_response>\n");

	
	memset(xml_begin, 0, BUF_SIZE_1024);
	xmlbegin_len += sprintf(xml_begin + xmlbegin_len, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
	xmlbegin_len += sprintf(xml_begin + xmlbegin_len, "<url_preload_response sessionid=\"%s\">\n", task->sessionid);
	memset(hdr_buffer, 0, BUF_SIZE_4096);
	hdr_len += sprintf(hdr_buffer + hdr_len, "%s", xml_begin);
	total = task->buflen + hdr_len + xmlend_len;

	
	ptr = realloc(task->buf, total + 1);
	if (NULL == ptr)
	{
		plog(ERROR, "realloc() failed, ERROR=[%s]", strerror(errno));
		return -1;
	}
	task->buf = ptr;
	memmove(task->buf + hdr_len, task->buf, task->buflen);
	memcpy(task->buf, hdr_buffer, hdr_len);
	memcpy(task->buf + task->buflen + hdr_len, xml_end, xmlend_len);
	task->buf[total - 1] = '\0';
	task->buflen = strlen(task->buf);;

	return 0;
}




static int urlPreload2(task_t *task)
{
	url_node_t *cur = NULL;

	for (cur = task->urls.list; NULL != cur; cur = cur->next)
	{
		urlPreloadOne(task, cur);
	}
	//free(task->buf);
	//task->buf = NULL;
	return 0;
}

static int urlPreload(task_t *task)
{
	urlPreload2(task);

	packReportData(task);
	postResultToServer(task);
//	preloaderReleaseTask(task);
	return 0;
}





void mytaskrelease(task_t *task)
{
url_node_t *cur, *next;


free(task->buffer);
free(task->buf);
free(task->sessionid);

for (cur = task->urls.list; NULL != cur; cur = next)
{
	next = cur->next;
	free(cur->url);
	free(cur);
}

free(task);
}


void *  preloaderRecvHandle(void *args)
{
	peek_data_t peek;
	task_t *task = NULL;
	int sockfd = (int)args;
	ssize_t ret, size, retry = 5;


	//detectEpollCall(EPOLL_DEL, sockfd, 0, NULL);				
	
	task = malloc(sizeof(struct task_st));
	memset(task, 0, sizeof(struct task_st));
	if(task == NULL)
	{
		plog(ERROR, "malloc task error");
		pthread_detach(pthread_self());
		return NULL;
	}

	task->sockfd = sockfd;
	
	memset(&peek, 0, sizeof(struct peerk_data_st));
	if (preloaderPeekMsgHeaders(sockfd, &peek) < 0)
	{
		plog(ERROR, "preloaderPeekMsgHeaders() failed");
		free(task);
		pthread_detach(pthread_self());
		return NULL;
	}
	
	size = peek.hdrlen + peek.contlen;

	task->buffer = calloc(size + BUF_SIZE_128, 1);
	if (NULL == task->buffer)
	{
		plog(ERROR, "calloc() for task.buffer failed, ERROR=[%s]", strerror(errno));
		free(task);
		pthread_detach(pthread_self());
		return NULL;
	}
	memset(task->buffer, 0, size+BUF_SIZE_128);
	
	task->recvlen = 0;

	do {
		ret = recv(sockfd, task->buffer + task->recvlen, size, 0);
		if (ret < 0)
		{       
			if (EAGAIN == errno)
			{
				plog(ERROR, "recv EAGAIN");
				free(task->buffer);
				free(task);
				pthread_detach(pthread_self());
				return NULL;
			}
			if (EINTR == errno && --retry)
			{       
				usleep(1000);
				plog(WARNING, "EINTR == errno");
				continue;
			}
			free(task->buffer);           
			free(task);
			pthread_detach(pthread_self());
			return NULL;
		}
		if (0 == ret)
		{
			if (task->recvlen < size)
			{
				plog(ERROR, "recv::ret == 0");
				free(task->buffer);
				free(task);
				pthread_detach(pthread_self());
				return NULL;
			}
		}
		task->recvlen += ret;
		size -= ret;
		if (0 == size)
			break;
	} while (1);

	
	if(peek.hdrlen + peek.contlen == strlen(task->buffer))
	{
		send(sockfd,"receive success", 16, 0);
		plog(COMMON, "receive success");
		printf("receive success\n");
		close(sockfd);
	}
	else
	{
		plog(ERROR, "receive not success");
		send(sockfd,"receive not success\n", 21, 0);
		close(sockfd);
	}
	


	

	if (preloaderParseMsgBody(task, &peek) < 0)
	{
		printf("preloaderParseMsgBody error\n");
		plog(ERROR, "preloaderParseMsgBody error\n");
		free(task->buffer);
		free(task);
		pthread_detach(pthread_self());
		return NULL;

	}


//	preloaderSafeFree((void *)&task->buffer);
	task->recvlen = 0;
	urlPreload(task);

	free(task->buf);
	task->buf = NULL;




	url_node_t *tmp=NULL;
	url_node_t *tmpnext=NULL;


	for(tmp=task->urls.head; tmp!=NULL; tmp=tmpnext)
	{
		tmpnext = tmp->next;
	//	printf("url ::%s\n", tmp->url);
		free(tmp->url);
	//	printf("tmp->url is free\n");
		free(tmp);
	//	printf("tmp is free\n");
	}

	free(task->buffer);
	free(task->sessionid);
	free(task);

	pthread_detach(pthread_self());
	sem_post(&thread_number);
	//plog(COMMON, "sem_post::%d", thread_number);
	pthread_exit(NULL);


//	preloaderReleaseTask(task);

}





















//int inu = 0;
static int preloaderEpollWaitHandle(const int type, int sockfd)
{

	switch (type)
	{
		case EPOLL_IN:
			if (sockfd == preloader.listenfd)
				{
				preloaderAcceptHandle(sockfd);
				plog(COMMON, "11111111111111111111111");
				break;
				}
			else
				{
					pthread_t tid;
					
					//plog(COMMON, "sem_wait before::%d", thread_number);
					sem_wait(&thread_number);
					pthread_create(&tid, NULL, (void *)preloaderRecvHandle, (void *)sockfd);
					detectEpollCall(EPOLL_DEL, sockfd, 0, NULL);				
				//	pthread_join(tid, NULL);	

					break;
				}
		case EPOLL_OUT:
			break;
		case EPOLL_ERR:
			break;
		case EPOLL_HUP:
			break;
		default:
			break;
	}
	return 0;
}


static int preloaderListenLoop(void)
{
	do {    
		usleep(1);
		detectEpollCall(EPOLL_WAIT, 0, 0, preloaderEpollWaitHandle);
	} while (1);
	detectEpollCall(EPOLL_DESTROY, 0, 0, NULL);

	return 0;
}

int preloaderCloseSockfdOnexec(int sockfd)
{
	int flags;
	int dummy = 0;

	if ((flags = fcntl(sockfd, F_GETFL, dummy)) < 0)
		return -1;
	if (fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC) < 0)
		return -1;

	return 0;
}

static int preloaderSetListener(void)
{
	int ret;
	int value = 1;
	struct sockaddr_in local;

	preloader.listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (preloader.listenfd < 0)
		return -1;
	memset(&local, 0, sizeof(struct sockaddr_in));
	local.sin_family = AF_INET;
	local.sin_port = htons(preloader.port);
	ret = inet_pton(AF_INET, LOCAL_DEFAULT_IP, &local.sin_addr);
	if (0 == ret)
		plog(ERROR, "local ip is invalid, IP=[0.0.0.0]");
	if (0 > ret)
		plog(ERROR, "inet_pton() failed, ERROR=[%s]", strerror(errno));
	if (setsockopt(preloader.listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&value, sizeof(value)) < 0)
		plog(WARNING, "setsockopt(SO_REUSEADDR) failed, ERROR=[%s]", strerror(errno));
	preloaderCloseSockfdOnexec(preloader.listenfd);
	if (bind(preloader.listenfd, (struct sockaddr *)&local, sizeof(local)) < 0)
	{
		plog(ERROR, "bind() failed, ERROR=[%s]", strerror(errno));
		close(preloader.listenfd);
		return -1;
	}
	if(listen(preloader.listenfd, PRELOADER_MAX_EVENTS) < 0)
	{
		plog(ERROR, "listen() failed, ERROR=[%s]", strerror(errno));
		close(preloader.listenfd);
		return -1;
	}
	if (setSockfdNonblocking(preloader.listenfd) < 0)
	{
		close(preloader.listenfd);
		return -1;
	}
	detectEpollCall(EPOLL_ADD, preloader.listenfd, EPOLLIN|EPOLLERR|EPOLLHUP, NULL);

	return 0;
}

static void preloaderTryWritePid(void)
{
	time_t tm; 
	int fd, val;
	struct stat st;
	struct flock lock;
	char buf[BUF_SIZE_256];

	if (stat(PRELOADER_PID_DIR, &st) < 0)
	{
		if (mkdir(PRELOADER_PID_DIR, S_IRWXU) < 0)
		{       
			fprintf(stderr, "mkdir() failed, DIR=[%s], ERROR=[%s]\n",
					PRELOADER_PID_DIR, strerror(errno));
			goto EXIT;
		}           
	}
	fd = open(PRELOADER_PID_FILE, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
	if(fd < 0)
	{
		plog(WARNING, "open(pidfile) failed, ERROR=[%s]", strerror(errno));
		goto EXIT; 
	}
	//set file write lock
	lock.l_len = 0;
	lock.l_start = 0;
	lock.l_type = F_WRLCK;
	lock.l_whence = SEEK_SET;
	if (fcntl(fd, F_SETLK, &lock) < 0)
	{
		fprintf(stderr, "Already have one preloader instance running!\n");
		plog(WARNING, "Already have one preloader instance running");
		goto EXIT;
	}
	if(ftruncate(fd, 0) < 0)
	{
		plog(WARNING, "truncate(pidfile) failed, ERROR=[%s]", strerror(errno));
		goto EXIT;
	}
	tm = time(NULL);
	memset(buf, 0, BUF_SIZE_256);
	sprintf(buf, "%d\n%ld\n", getpid(), tm);
	if(write(fd, buf, strlen(buf)) != strlen(buf))
	{
		plog(WARNING, "write(pidfile) failed, ERROR=[%s]", strerror(errno));
		goto EXIT;
	}
	val = fcntl(fd, F_GETFD, 0);
	if(val < 0)
	{
		plog(WARNING, "fcntl(F_GETFD) failed, ERROR=[%s]", strerror(errno));
		goto EXIT;
	}
	//set fd flag: close-on-exec
	val |= FD_CLOEXEC;
	if(fcntl(fd, F_SETFD, val) < 0)
	{
		plog(WARNING, "fcntl(F_SETFD) failed, ERROR=[%s]", strerror(errno));
		goto EXIT;
	}
	puts("try lock succeed");
	return;

EXIT:
	puts("try lock failed");
	exit(1);
}

void preloaderSetSelfDaemon(void)
{
	

	int fd;
	pid_t pid;

	fflush(NULL);
	pid = fork(); 
	if(pid < 0)
	{ 
		fprintf(stderr, "fork() for daemon failed, ERROR=[%s]", strerror(errno));
		exit(1);
	}
	if(pid > 0)
		exit(0);
	fd = open("/dev/null", O_RDWR);
	if (fd < 0)
	{	
		perror("open()");	
		fclose(stdin);
		//fclose(stdout);
		fclose(stderr);
	}
	else
	{	
		dup2(fd, 0);	
		//dup2(fd, 1);
		dup2(fd, 2);	
		if (fd>2) close(fd);
	}
	umask(0);
	chdir("/");
	setsid();
}




int main(int argc, char **argv)
{
	pthread_mutex_init(&mylock, NULL);
	pthread_mutex_init(&myfilelock, NULL);

	memset(&preloader, 0, sizeof(preloader));
	preloaderParseOptions(argc, argv);
	preloaderSetSelfDaemon();
	preloaderTryWritePid();
	preloaderResetRlimit();
	preloaderVarInit();
	sem_init(&thread_number, 0, 1000);
	
	openLogFile();
	preloaderKillRunningPort(preloader.port);
	printf("11111111111111111111111111111111111111111\n");
	checkDirectory(store_dir);
	getDevId();

	if (preloaderSetListener() < 0)
		exit(1);

	preloaderListenLoop();
	return 0;
}

